package com.itheima.task.service.impl;

import com.alibaba.fastjson.JSON;
import com.itheima.common.llm.GreenContentScan;
import com.itheima.common.redis.CacheService;
import com.itheima.file.service.FileStorageService;
import com.itheima.model.audit.enums.AuditStatus;
import com.itheima.model.audit.pojos.AuditTask;
import com.itheima.model.common.dtos.ResponseResult;
import com.itheima.model.common.enums.AppHttpCodeEnum;
import com.itheima.task.config.KafkaConfig;
import com.itheima.task.service.AuditService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;

/**
 * 审核服务实现
 */
@Service
@Slf4j
public class AuditServiceImpl implements AuditService {

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private CacheService cacheService;

    @Autowired
    private KafkaTemplate<String, String> kafkaTemplate;

    @Autowired
    private GreenContentScan greenContentScan;

    @Autowired
    private FileStorageService fileStorageService;

    @Value("${audit.high-confidence:0.7}")
    private double highConfidence;

    @Value("${audit.low-confidence:0.3}")
    private double lowConfidence;

    @Value("${audit.max-retry:3}")
    private int maxRetry;

    @Override
    public void executeAudit(AuditTask task) {
        try {
            log.info("开始执行AI审核: taskId={}, contentType={}, contentId={}", 
                    task.getTaskId(), task.getContentType(), task.getContentId());

            // 1. 更新状态为 AI 审核中
            task.setAuditStatus(AuditStatus.AI_AUDITING.getCode());
            task.setUpdateTime(new Date());
            mongoTemplate.save(task);

            // 2. 调用 AI 审核 API
            AuditResult aiResult = callAIAudit(task);

            // 3. 根据 AI 结果和置信度判断
            processAIResult(task, aiResult);

            log.info("AI审核完成: taskId={}, result={}, confidence={}", 
                    task.getTaskId(), aiResult.suggestion, aiResult.confidence);

        } catch (Exception e) {
            log.error("AI审核失败: taskId={}", task.getTaskId(), e);
            handleAuditFailure(task, e);
        }
    }

    @Override
    public ResponseResult manualPass(String taskId, Integer auditorId, String comment) {
        try {
            // 1. 查询任务
            Query query = new Query(Criteria.where("taskId").is(taskId));
            AuditTask task = mongoTemplate.findOne(query, AuditTask.class);

            if (task == null) {
                return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "任务不存在");
            }

            // 2. 更新审核状态
            task.setAuditStatus(AuditStatus.MANUAL_PASS.getCode());
            task.setAuditorId(auditorId);
            task.setAuditComment(comment);
            task.setUpdateTime(new Date());
            mongoTemplate.save(task);

            // 3. 更新缓存
            cacheService.hPut(KafkaConfig.Keys.TASK_STATUS_CACHE, 
                    taskId, 
                    String.valueOf(AuditStatus.MANUAL_PASS.getCode()));

            // 4. 发送审核结果
            sendAuditResult(task, "PASS", "人工审核通过", 1.0);

            log.info("人工审核通过: taskId={}, auditorId={}", taskId, auditorId);
            return ResponseResult.okResult("审核通过");

        } catch (Exception e) {
            log.error("人工审核通过失败: taskId={}", taskId, e);
            return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR, "操作失败");
        }
    }

    @Override
    public ResponseResult manualReject(String taskId, Integer auditorId, String comment) {
        try {
            // 1. 查询任务
            Query query = new Query(Criteria.where("taskId").is(taskId));
            AuditTask task = mongoTemplate.findOne(query, AuditTask.class);

            if (task == null) {
                return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "任务不存在");
            }

            // 2. 更新审核状态
            task.setAuditStatus(AuditStatus.MANUAL_REJECT.getCode());
            task.setAuditorId(auditorId);
            task.setAuditComment(comment);
            task.setUpdateTime(new Date());
            mongoTemplate.save(task);

            // 3. 更新缓存
            cacheService.hPut(KafkaConfig.Keys.TASK_STATUS_CACHE, 
                    taskId, 
                    String.valueOf(AuditStatus.MANUAL_REJECT.getCode()));

            // 4. 发送审核结果
            sendAuditResult(task, "BLOCK", comment, 1.0);

            log.info("人工审核拒绝: taskId={}, auditorId={}, comment={}", taskId, auditorId, comment);
            return ResponseResult.okResult("审核拒绝");

        } catch (Exception e) {
            log.error("人工审核拒绝失败: taskId={}", taskId, e);
            return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR, "操作失败");
        }
    }

    @Override
    public ResponseResult getPendingManualAuditTasks(Integer page, Integer size) {
        try {
            // 1. 构建查询条件
            Query query = new Query(Criteria.where("auditStatus").is(AuditStatus.MANUAL_PENDING.getCode()));
            
            // 2. 分页
            query.with(PageRequest.of(page - 1, size));
            
            // 3. 按创建时间倒序
            query.with(org.springframework.data.domain.Sort.by(
                    org.springframework.data.domain.Sort.Direction.DESC, "createTime"));

            // 4. 查询
            List<AuditTask> tasks = mongoTemplate.find(query, AuditTask.class);
            long total = mongoTemplate.count(query, AuditTask.class);

            // 5. 构建返回结果
            Map<String, Object> result = new HashMap<>();
            result.put("tasks", tasks);
            result.put("total", total);
            result.put("page", page);
            result.put("size", size);

            return ResponseResult.okResult(result);

        } catch (Exception e) {
            log.error("查询待审核任务失败", e);
            return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR, "查询失败");
        }
    }

    /**
     * 调用 AI 审核 API
     */
    private AuditResult callAIAudit(AuditTask task) {
        log.info("调用AI审核API: taskId={}, textLength={}, imageCount={}", 
                task.getTaskId(), 
                task.getTextContent() != null ? task.getTextContent().length() : 0,
                task.getImageUrls() != null ? task.getImageUrls().size() : 0);

        AuditResult result = new AuditResult();
        result.suggestion = "PASS";
        result.label = "正常内容";
        result.confidence = 1.0;

        // ==================== 模拟审核（默认通过）====================
        /*
        log.info("✅ 模拟审核通过: taskId={}", task.getTaskId());
        return result;
        */
        
        // ==================== 真实 AI 审核 ====================
        try {
            // 1. 文本内容审核
            if (StringUtils.hasText(task.getTextContent())) {
                Map<String, String> textResult = greenContentScan.textScan(task.getTextContent());
                
                if (textResult == null) {
                    // API 调用失败，记录详细错误信息
                    log.error("文本审核API调用失败: taskId={}, apiKey={}, apiUrl={}", 
                            task.getTaskId(),
                            greenContentScan.getApiKey() != null ? "已配置" : "未配置",
                            greenContentScan.getApiUrl());
                    throw new RuntimeException("文本审核API调用失败，请检查LLM配置和网络连接");
                }
                
                String textSuggestion = textResult.get("suggestion");
                String textLabel = textResult.get("label");
                
                log.info("文本审核结果: taskId={}, suggestion={}, label={}", 
                        task.getTaskId(), textSuggestion, textLabel);
                
                // 如果文本审核不通过，直接返回
                if (!"PASS".equals(textSuggestion)) {
                    result.suggestion = convertRiskLevel(textSuggestion);
                    result.label = textLabel != null ? textLabel : "内容违规";
                    result.confidence = calculateConfidence(textSuggestion);
                    return result;
                }
            }

            // 2. 图片内容审核
            if (!CollectionUtils.isEmpty(task.getImageUrls())) {
                List<byte[]> imageBytes = downloadImages(task.getImageUrls());
                
                if (!imageBytes.isEmpty()) {
                    Map<String, String> imageResult = greenContentScan.imageScan(imageBytes);
                    
                    if (imageResult == null) {
                        // API 调用失败，抛出异常触发重试
                        throw new RuntimeException("图片审核API调用失败");
                    }
                    
                    String imageSuggestion = imageResult.get("suggestion");
                    String imageLabel = imageResult.get("label");
                    
                    log.info("图片审核结果: taskId={}, suggestion={}, label={}", 
                            task.getTaskId(), imageSuggestion, imageLabel);
                    
                    // 如果图片审核不通过，返回
                    if (!"PASS".equals(imageSuggestion)) {
                        result.suggestion = convertRiskLevel(imageSuggestion);
                        result.label = imageLabel != null ? imageLabel : "图片违规";
                        result.confidence = calculateConfidence(imageSuggestion);
                        return result;
                    }
                }
            }

            // 3. 所有检查通过
            log.info("内容审核通过: taskId={}", task.getTaskId());
            return result;

        } catch (Exception e) {
            log.error("AI审核过程异常: taskId={}", task.getTaskId(), e);
            throw new RuntimeException("AI审核异常: " + e.getMessage(), e);
        }
    }

    /**
     * 下载图片内容
     */
    private List<byte[]> downloadImages(List<String> imageUrls) {
        List<byte[]> imageBytes = new ArrayList<>();
        
        for (String imageUrl : imageUrls) {
            try {
                byte[] bytes = fileStorageService.downLoadFile(imageUrl);
                if (bytes != null && bytes.length > 0) {
                    imageBytes.add(bytes);
                    log.debug("成功下载图片: url={}, size={}KB", imageUrl, bytes.length / 1024);
                } else {
                    log.warn("下载图片为空: url={}", imageUrl);
                }
            } catch (Exception e) {
                log.error("下载图片异常: url={}", imageUrl, e);
                // 继续处理其他图片
            }
        }
        
        return imageBytes;
    }

    /**
     * 转换风险等级为建议
     * @param riskLevel 风险等级 (HIGH/MEDIUM/LOW)
     * @return 建议 (BLOCK/REVIEW/PASS)
     */
    private String convertRiskLevel(String riskLevel) {
        if ("HIGH".equalsIgnoreCase(riskLevel)) {
            return "BLOCK";
        } else if ("MEDIUM".equalsIgnoreCase(riskLevel)) {
            return "REVIEW";
        }
        return "PASS";
    }

    /**
     * 根据风险等级计算置信度
     * @param riskLevel 风险等级
     * @return 置信度 (0-1)
     */
    private double calculateConfidence(String riskLevel) {
        if ("HIGH".equalsIgnoreCase(riskLevel)) {
            return 0.9;  // 高风险，高置信度
        } else if ("MEDIUM".equalsIgnoreCase(riskLevel)) {
            return 0.5;  // 中风险，中置信度
        } else if ("LOW".equalsIgnoreCase(riskLevel)) {
            return 0.3;  // 低风险，低置信度
        }
        return 1.0;  // PASS，满分置信度
    }

    /**
     * 处理 AI 审核结果
     */
    private void processAIResult(AuditTask task, AuditResult aiResult) {
        task.setAiSuggestion(aiResult.suggestion);
        task.setAiLabel(aiResult.label);
        task.setAiConfidence(aiResult.confidence);

        // 根据置信度判断
        if (aiResult.confidence >= highConfidence) {
            // 高置信度：直接采纳 AI 结果
            if ("PASS".equals(aiResult.suggestion)) {
                task.setAuditStatus(AuditStatus.AI_PASS.getCode());
                sendAuditResult(task, "PASS", aiResult.label, aiResult.confidence);
            } else {
                task.setAuditStatus(AuditStatus.AI_REJECT.getCode());
                sendAuditResult(task, "BLOCK", aiResult.label, aiResult.confidence);
            }
        } else if (aiResult.confidence >= lowConfidence) {
            // 中置信度：转人工审核
            task.setAuditStatus(AuditStatus.MANUAL_PENDING.getCode());
            log.info("AI置信度不足，转人工审核: taskId={}, confidence={}", 
                    task.getTaskId(), aiResult.confidence);
        } else {
            // 低置信度：也采纳 AI 结果（因为很确定是正常内容）
            if ("PASS".equals(aiResult.suggestion)) {
                task.setAuditStatus(AuditStatus.AI_PASS.getCode());
                sendAuditResult(task, "PASS", aiResult.label, aiResult.confidence);
            } else {
                task.setAuditStatus(AuditStatus.AI_REJECT.getCode());
                sendAuditResult(task, "BLOCK", aiResult.label, aiResult.confidence);
            }
        }

        task.setUpdateTime(new Date());
        mongoTemplate.save(task);

        // 更新缓存
        cacheService.hPut(KafkaConfig.Keys.TASK_STATUS_CACHE, 
                task.getTaskId(), 
                String.valueOf(task.getAuditStatus()));
    }

    /**
     * 处理审核失败
     */
    private void handleAuditFailure(AuditTask task, Exception e) {
        int retryCount = task.getRetryCount() != null ? task.getRetryCount() : 0;
        
        if (retryCount < maxRetry) {
            // 失败重试：指数退避
            task.setRetryCount(retryCount + 1);
            task.setAuditStatus(AuditStatus.RETRY.getCode());
            task.setUpdateTime(new Date());
            mongoTemplate.save(task);

            // 重新加入延迟队列（延迟时间：2^retryCount 秒）
            long delaySeconds = (long) Math.pow(2, retryCount);
            long executeTime = System.currentTimeMillis() + delaySeconds * 1000;
            
            cacheService.zAdd(KafkaConfig.Keys.DELAY_QUEUE_AUDIT_TASKS, 
                    task.getTaskId(), executeTime);

            log.warn("审核失败，将重试: taskId={}, retryCount={}, delaySeconds={}", 
                    task.getTaskId(), retryCount + 1, delaySeconds);

        } else {
            // 超过最大重试次数，标记为失败
            task.setAuditStatus(AuditStatus.FAILED.getCode());
            task.setUpdateTime(new Date());
            mongoTemplate.save(task);

            // 更新缓存
            cacheService.hPut(KafkaConfig.Keys.TASK_STATUS_CACHE, 
                    task.getTaskId(), 
                    String.valueOf(AuditStatus.FAILED.getCode()));

            log.error("审核失败，已达最大重试次数: taskId={}, retryCount={}", 
                    task.getTaskId(), retryCount);
        }
    }

    /**
     * 发送审核结果到 Kafka
     */
    private void sendAuditResult(AuditTask task, String suggestion, String label, double confidence) {
        try {
            Map<String, Object> result = new HashMap<>();
            result.put("taskId", task.getTaskId());
            result.put("contentType", task.getContentType());
            result.put("contentId", task.getContentId());
            result.put("userId", task.getUserId());
            result.put("auditStatus", task.getAuditStatus());
            result.put("suggestion", suggestion);
            result.put("label", label);
            result.put("confidence", confidence);
            result.put("timestamp", System.currentTimeMillis());

            String resultJson = JSON.toJSONString(result);
            String key = task.getContentType() + ":" + task.getContentId();

            kafkaTemplate.send(KafkaConfig.Topics.AUDIT_RESULT, key, resultJson)
                    .addCallback(
                            success -> log.info("发送审核结果成功: taskId={}, key={}", task.getTaskId(), key),
                            failure -> log.error("发送审核结果失败: taskId={}, key={}", task.getTaskId(), key, failure)
                    );

        } catch (Exception e) {
            log.error("发送审核结果失败: taskId={}", task.getTaskId(), e);
        }
    }

    /**
     * AI 审核结果内部类
     */
    private static class AuditResult {
        public String suggestion;  // PASS/BLOCK/REVIEW
        public String label;       // 违规类型
        public double confidence;  // 置信度
    }
}

